package xin.nick.service;

import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xin.nick.config.SystemConstants;
import xin.nick.domain.dto.LoginDTO;
import xin.nick.domain.vo.LoginUserVO;
import xin.nick.entity.LoginUser;
import xin.nick.entity.ResultCode;
import xin.nick.manager.LoginManager;
import xin.nick.security.SecurityUtil;
import xin.nick.util.MyAssert;

/**
 * @author Nick
 * @since 2023/1/3
 */
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class LoginService {

    private final AuthenticationManager authenticationManager;
    private final LoginManager loginManager;
    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 用户登录
     * @param loginDTO LoginDTO
     * @return LoginUserVO
     */
    public LoginUserVO login(LoginDTO loginDTO) {
        String username = loginDTO.getUsername();
        String password = loginDTO.getPassword();

        // 用户验证
        Authentication authentication;

        // 该方法会去调用 CustomUserDetailsService.loadUserByUsername
        authentication = authenticationManager
                .authenticate(new UsernamePasswordAuthenticationToken(username, password));

        // authentication 不会返回为空,如果为空,会直接跳异常,而不会返回
        // 强迫症,还是多加个判断吧
        MyAssert.notNull(authentication, ResultCode.ACCOUNT_OR_PASSWORD_ERROR);
        LoginUser loginUser = null;
        Object principal = authentication.getPrincipal();
        if (principal instanceof LoginUser) {
            loginUser = (LoginUser) authentication.getPrincipal();
        }
        MyAssert.notNull(loginUser, ResultCode.ACCOUNT_OR_PASSWORD_ERROR);

        // 登录成功之后,设置token
        loginManager.setLoginUserToken(loginUser);

        // 返回对象
        return buildLoginUserVO(loginUser);
    }


    /**
     * 退出登录
     */
    public void logout() {
        Long userId = SecurityUtil.getCurrentUserId();
        String tokenKey = SystemConstants.USER_TOKEN_KEY + userId;
        redisTemplate.delete(tokenKey);
    }


    /**
     * 构建返回对象
     * @param loginUser LoginUser
     * @return LoginUserVO
     */
    private LoginUserVO buildLoginUserVO(LoginUser loginUser) {
        Long userId = loginUser.getUserId();

        // 返回对象
        LoginUserVO loginUserVO = new LoginUserVO();
        loginUserVO.setToken(loginUser.getToken());
        loginUserVO.setId(userId);
        loginUserVO.setUsername(loginUser.getUsername());
        loginUserVO.setNickname(loginUser.getNickname());

        return loginUserVO;
    }
}
